#include <stdio.h>
#include <stdlib.h>

#include <time.h>
#include <Math.h>

#include <GL/gl.h>     // The GL Header File
#include <GL/glut.h>   // The GL Utility Toolkit (Glut) Header

#include "GameEntity.h"
#include "GameLoopConstants.h"

#define Z_MAIN_DRAW_PLANE -3
#define SPEED 10

GLfloat SQUARE_COLOR_RED[3] = {0.7f, 0.0f, 0.0f};
GLfloat SQUARE_COLOR_BLUE[3] = {0.0f, 0.7f, 0.0f};

GameEntity* GameEntity_new(float startX, float startY, float width, float height, int colorSwitchIntervalMs) {
	GameEntity* gameEntity = malloc(sizeof(GameEntity));
	gameEntity->startX = startX;
	gameEntity->startY = startY;
	gameEntity->width = width;
	gameEntity->height = height;
	gameEntity->colorSwitchIntervalMs = colorSwitchIntervalMs;
	gameEntity->currentColor = SQUARE_COLOR_RED;
	gameEntity->stateUpdatesAccumulator = 0;

	gameEntity->updateStateGlobalStartTime = 0;
	gameEntity->updateStateGlobalCounter = 0;
	gameEntity->precision = 0;

	return gameEntity;
}

void GameEntity_updateState(GameEntity* gameEntity, ArrowKeyPressedEvent* inputEvent) {
	GameEntity_updatePrecisionMeasurement(gameEntity);

	gameEntity->stateUpdatesAccumulator++;

	if(inputEvent!=NULL) {
		if(inputEvent->arrow=='L') {
			gameEntity->startX -= SPEED;
		}
		if(inputEvent->arrow=='R') {
			gameEntity->startX += SPEED;
		}
		if(inputEvent->arrow=='U') {
			gameEntity->startY += SPEED;
		}
		if(inputEvent->arrow=='D') {
			gameEntity->startY -= SPEED;
		}
	}

	if(gameEntity->stateUpdatesAccumulator * DESIRED_STATE_UPDATE_DURATION_MS >= gameEntity->colorSwitchIntervalMs) {
		if(gameEntity->currentColor == SQUARE_COLOR_RED) {
			gameEntity->currentColor = SQUARE_COLOR_BLUE;
		} else {
			gameEntity->currentColor = SQUARE_COLOR_RED;
		}
		gameEntity->stateUpdatesAccumulator = 0;
	}
}

void GameEntity_updateGraphics(GameEntity* gameEntity) {
	float x1 = gameEntity->startX;
	float y1 = gameEntity->startY;//upper left

	float x2 = gameEntity->startX;
	float y2 = gameEntity->startY - gameEntity->height; //lower left

	float x3 = gameEntity->startX + gameEntity->width;
	float y3 = gameEntity->startY - gameEntity->height; // lower right

	float x4 = gameEntity->startX + gameEntity->width;
	float y4 = gameEntity->startY; // upper right

	glBegin(GL_QUADS);
		glColor3fv(gameEntity->currentColor);
		glVertex3f(x1, y1, Z_MAIN_DRAW_PLANE);
		glVertex3f(x2, y2, Z_MAIN_DRAW_PLANE);
		glVertex3f(x3, y3, Z_MAIN_DRAW_PLANE);
		glVertex3f(x4, y4, Z_MAIN_DRAW_PLANE);
	glEnd();
}

void GameEntity_updatePrecisionMeasurement(GameEntity* gameEntity) {
	gameEntity->updateStateGlobalCounter++;
	if(gameEntity->updateStateGlobalStartTime==0) {
		gameEntity->updateStateGlobalStartTime = glutGet(GLUT_ELAPSED_TIME);
	} else {
		if(gameEntity->updateStateGlobalCounter % 25 == 0) {
			double now = glutGet(GLUT_ELAPSED_TIME);
			double timeElapsedMs = (now-gameEntity->updateStateGlobalStartTime)/(CLOCKS_PER_SEC);
			double actualUpdateStateFrequency = gameEntity->updateStateGlobalCounter/timeElapsedMs;
			double desiredUpdateStateFrequency = DESIRED_STATE_UPDATES_PER_SECOND;
			gameEntity->precision = (fmin(actualUpdateStateFrequency, desiredUpdateStateFrequency)/fmax(actualUpdateStateFrequency, desiredUpdateStateFrequency))*100.0f;
		}
	}
}

void GameEntity_free(GameEntity* gameEntity) {
	free(gameEntity->currentColor);
	free(gameEntity);
}


